<?php

declare(strict_types=1);

namespace app\api\controller;
use app\common\model\Order as OrderModel;
use app\common\model\ProductOrder;
use app\common\model\UserRecharge;
use Payment\Config;
use Payment\Client\Charge;
use think\facade\Db;
class Pay extends Base
{

    public function __construct()
    {
        $config = getConfig('weixinpay');
        $this->appid = $config['appid'];
        $this->merchant = $config['mch_id'];
        $this->secretKey = $config['keys'];
        $this->noticeurl = request()->domain() . '/api/notify/order_notify'; #订单回调URL
    }

    //支付
    /**
     * [pay description]
     * @param  [type] $uid       [用户 的id]
     * @param  [type] $order_num [订单号]
     * @param  [pay_type]        [支付类型 1 微信 ]
     * @return [type]            [支付来源  1 盲盒订单 2运费 3 余额充值 4 积分商城支付]
     */
    public function pay($order_num, $title, $openid, $type)
    {
        if ($type == 1) {
            $order = OrderModel::getInfo(['order_num' => $order_num]);
            if ($order['status'] != 1) {
                return $this->renderError("参数错误");
            }
            $total = $order['total_price'];
            if ($total > 0) {
                $notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify1';
                return $this->wxpay($order_num, $total, "支付订单-" . $title, $openid, $notify);
            } else {
                // if($order['money'] > 0){
                // 				User::changeMoney($order['user_id'],'-'.$order['money'],3);
                // 			}
                // 			if($order['integral'] > 0){
                // 				User::changeIntegral($order['user_id'],'-'.$order['integral'],3);
                // 			}

                $notify = new \app\api\controller\Notify($this->app);
                $data = $notify->order_update($order_num, 1);

                if ($data == 1) {
                    $data = [];
                    $data['is_weixin'] = 2;
                    return json_encode($data);
                }
            }
        } elseif ($type == 2) {
            //发货订单支付运费
            $config = getConfig("base");
            $total = $config['post_money'];   //邮费
            $notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify2';
            return $this->wxpay($order_num, $total, $title, $openid, $notify);
        } elseif ($type == 3) {
            //余额充值
            $order = UserRecharge::getInfo(['order_num' => $order_num]);
            $total = $order['money'];
            $notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify3';
            return $this->wxpay($order_num, $total, $title, $openid, $notify);
        } elseif ($type == 4) {
            //积分 商城购买
            $order = ProductOrder::getInfo(['order_num' => $order_num]);
            $total = $order['total_money'];
            $notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify4';
            return $this->wxpay($order_num, $total, $title, $openid, $notify);
        } elseif ($type == 5) {
            //集市下单
            $order = OrderModel::getInfo(['order_num' => $order_num]);
            if ($order['status'] != 1) {
                return $this->renderError("参数错2误");
            }
            $total = $order['total_price'];
            if ($total > 0) {
                $notify = 'http://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify5';
                return $this->wxpay($order_num, $total, "支付订单-" . $title, $openid, $notify);
            } else {
                $notify = new \app\api\controller\Notify($this->app);
                $data = $notify->order_update($order_num, 5);
                if ($data == 1) {
                    $data = [];
                    $data['is_weixin'] = 2;
                    return json_encode($data);
                }
            }
        } elseif ($type == 6) {
            $order = OrderModel::getInfo(['order_num' => $order_num]);
            if ($order['status'] != 1) {
                return $this->renderError("参数错误");
            }
            $total = $order['total_price'];
            if ($total > 0) {
                $notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify6';
                return $this->wxpay($order_num, $total, "支付订单-" . $title, $openid, $notify);
            } else {
                $notify = new \app\api\controller\Notify($this->app);
                $data = $notify->order_update($order_num, 6);
                if ($data == 1) {
                    $data = [];
                    $data['is_weixin'] = 2;
                    return json_encode($data);
                }
            }
        } elseif ($type == 7) {
            $order = Db::name('kk_order')->where('order_no', $order_num)->find();
            if ($order['status'] !== 0) {
                return $this->renderError("参数错误");
            }
            $total = $order['price'];
            if ($total > 0) {
                $notify = 'https://' . $_SERVER['HTTP_HOST'] . '/api/notify/order_notify7';
                return $this->wxpay($order_num, $total, "秒杀商城订单-" . $title, $openid, $notify);
            } else {
                //                dd($this->app);
                //                $notify = new Notify($this->app);
                $res = Notify::order_update($order_num, 7);
                $data['res'] = $res;
                $data['is_weixin'] = 2;
                return json_encode($data);
            }
        }
    }



    //支付
    public function wxpay($order_num, $money, $title, $openid, $notify)
    {

        $body = mb_substr($title, 0, 30);
        // $notifyUrl = $this->noticeurl;
        $nonce_str = $this->genRandomString();
        $params['appid'] = $this->appid;
        $params['mch_id'] = $this->merchant;
        $params['nonce_str'] = $this->genRandomString();
        $params['body'] = $body;
        $params['attach'] = 'order_ckj';
        $params['out_trade_no'] = $order_num;
        $params['notify_url'] = $notify;
        $params['total_fee'] = round($money * 100, 2);
        // $params['total_fee'] = 1;
        $params['spbill_create_ip'] = $this->get_client_ip();
        $params['trade_type'] = 'JSAPI';
        $params['openid'] = $openid;
        $params['sign'] = $this->MakeSign($params);
        //  dd($params);
        $xml = $this->data_to_xml($params);
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $response = $this->postXmlCurl($xml, $url);
        $resData = $this->xml_to_data($response);
        // p($resData);

        if (!$resData || $resData['return_code'] != 'SUCCESS' || $resData['result_code'] != 'SUCCESS') {
            $return['status'] = 0;
            $return['msg'] = "网络故障，请稍后重试(支付参数错误)";
            return json_encode($return);
        } else {
            $return['appId'] = $resData['appid'];
            $return['nonceStr'] = $this->genRandomString();
            $return['package'] = 'prepay_id=' . $resData['prepay_id'];
            $return['signType'] = 'MD5';
            $return['timeStamp'] = (string) time();
            $return['paySign'] = $this->MakeSign($return);
            $return['is_weixin'] = 1;
            return json_encode($return);
        }
    }
    /**
     * 微信小程序下单方法
     * @param   $params 下单参数
     */
    public function wxCreateOrder($order_no, $price, $openid, $body, $attach)
    {
        $body = mb_substr($body, 0, 30);
        $notifyUrl = $this->noticeurl;
        $nonce_str = $this->genRandomString();
        $params['appid'] = $this->appid;
        $params['mch_id'] = $this->merchant;
        $params['nonce_str'] = $this->genRandomString();
        $params['body'] = $body;
        $params['attach'] = $attach;
        $params['out_trade_no'] = $order_no;
        $params['notify_url'] = $notifyUrl;
        $params['total_fee'] = round($price * 100, 2);
        // $params['total_fee'] = 1;
        $params['spbill_create_ip'] = $this->get_client_ip();
        $params['trade_type'] = 'JSAPI';
        $params['openid'] = $openid;
        $params['sign'] = $this->MakeSign($params);

        $xml = $this->data_to_xml($params);
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $response = $this->postXmlCurl($xml, $url);
        $result = $this->xml_to_data($response);
        if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
            $time = time();
            $res['appId'] = $this->appid;
            $res["timeStamp"] = (string) $time;
            $res["nonceStr"] = $nonce_str;
            $res["package"] = "prepay_id=" . $result['prepay_id'];
            $res["signType"] = 'MD5';
            $res["paySign"] = $this->MakeSign($res);
            return ['status' => 1, 'data' => $res];
        } else {
            return ['status' => 0, 'msg' => '支付失败'];
        }
    }


    /**
     * 生成签名
     * @return 签名
     */
    public function MakeSign($params)
    {
        //签名步骤一：按字典序排序数组参数
        ksort($params);
        $string = $this->ToUrlParams($params);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . $this->secretKey;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     * 将参数拼接为url: key=value&key=value
     * @param   $params
     * @return  string
     */
    public function ToUrlParams($params)
    {
        $string = '';
        if (!empty($params)) {
            $array = array();
            foreach ($params as $key => $value) {
                $array[] = $key . '=' . $value;
            }
            $string = implode("&", $array);
        }
        return $string;
    }

    /**
     * 输出xml字符
     * @param   $params     参数名称
     * return   string      返回组装的xml
     **/
    public function data_to_xml($params)
    {
        if (!is_array($params) || count($params) <= 0) {
            return false;
        }
        $xml = "<xml>";
        foreach ($params as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 将xml转为array
     * @param string $xml
     * return array
     */
    public function xml_to_data($xml)
    {
        if (!$xml) {
            return false;
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }

    /**
     * 产生一个指定长度的随机字符串,并返回给用户
     * @param type $len 产生字符串的长度
     * @return string 随机字符串
     */
    private function genRandomString($len = 32)
    {
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );
        $charsLen = count($chars) - 1;
        // 将数组打乱
        shuffle($chars);
        $output = "";
        for ($i = 0; $i < $len; $i++) {
            $output .= $chars[mt_rand(0, $charsLen)];
        }
        return $output;
    }

    /**
     * 以post方式提交xml到对应的接口url
     *
     * @param string $xml 需要post的xml数据
     * @param string $url url
     * @param bool $useCert 是否需要证书，默认不需要
     * @param int $second url执行超时时间，默认30s
     * @throws WxPayException
     */
    private function postXmlCurl($xml, $url, $second = 30)
    {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            return false;
        }
    }

    /**
     * 错误代码
     * @param  $code       服务器输出的错误代码
     * return string
     */
    public function error_code($code)
    {
        $errList = array(
            'NOAUTH' => '商户未开通此接口权限',
            'NOTENOUGH' => '用户帐号余额不足',
            'ORDERNOTEXIST' => '订单号不存在',
            'ORDERPAID' => '商户订单已支付，无需重复操作',
            'ORDERCLOSED' => '当前订单已关闭，无法支付',
            'SYSTEMERROR' => '系统错误!系统超时',
            'APPID_NOT_EXIST' => '参数中缺少APPID',
            'MCHID_NOT_EXIST' => '参数中缺少MCHID',
            'APPID_MCHID_NOT_MATCH' => 'appid和mch_id不匹配',
            'LACK_PARAMS' => '缺少必要的请求参数',
            'OUT_TRADE_NO_USED' => '同一笔交易不能多次提交',
            'SIGNERROR' => '参数签名结果不正确',
            'XML_FORMAT_ERROR' => 'XML格式错误',
            'REQUIRE_POST_METHOD' => '未使用post传递参数 ',
            'POST_DATA_EMPTY' => 'post数据不能为空',
            'NOT_UTF8' => '未使用指定编码格式',
        );
        if (array_key_exists($code, $errList)) {
            return $errList[$code];
        }
    }

    function get_client_ip()
    {
        if (isset($_SERVER['REMOTE_ADDR'])) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "127.0.0.1";
        }
        return $cip;
    }
    public function zfpay($order_num, $price, $subject, $body)
    {

        $config  = config('payment');
        //生成订单
        $payData = [
            'body'            => $body, //对一笔交易的具体描述信息。
            'subject'         => $subject, //标题
            'order_no'        => $order_num, //订单号不可重复向支付宝发送
            'amount'          => $price, //单位：元
            'timeout_express' => time() + 15 * 60, //过期时间（当前时间+过期s数），必须大于当前支付请求时间
            'client_ip'       => request()->ip(),
            'goods_type'      => '1',    //0:虚拟商品 1:实物商品
            'return_param'    => 'recharge' //异步通知时原样返回的数据，不需要urlencode。不可包含特殊符号
        ];
        $pay_way = 'ali_wap'; //支付方式
        /**
         * Config::ALI_CHANNEL_WEB 	== 'ali_web'| 'wx_qr'
         * Config::ALI_CHARGE	 	== 'ali_charge'
         * Config::ALI_CHANNEL_WEB 	== 'wx_charge'
         */
        $type = $pay_way == Config::ALI_CHANNEL_WAP ? Config::ALI_CHARGE : Config::WX_CHARGE;
        // 调用payment组件接口 返回发起支付的url
        $payment_url = Charge::run($pay_way, $config[$type], $payData);
        return ['status' => 1, 'data' => $payment_url];
        // return $this->renderSuccess("成功", $payment_url);
    }
}
